//
//  CSCyclingRootViewController.swift
//  Cycling
//
//  Created by CSS on 4/5/23.
//

import UIKit
import MapboxCoreNavigation
import MapboxNavigation
import MapboxMaps
import MapboxDirections
import Turf
import YYModel
import MBProgressHUD

class CSCyclingRootViewController: UIViewController {

    @IBOutlet private weak var shapeContentView: UIView!
    @IBOutlet private weak var commandSignView: UIImageView!
    @IBOutlet private weak var commandNameLbl: UILabel!
    @IBOutlet private weak var commandRemainingLbl: UILabel!
    @IBOutlet private weak var endButton: UIButton!
    @IBOutlet private weak var pauseButton: UIButton!
    
    @IBOutlet private weak var mapContentStackView: UIStackView!
    @IBOutlet private weak var showOriginButton: UIButton!
    
    // MARK: 正在运行部分
    
    @IBOutlet private weak var totalDistanceLbl: UILabel!
    @IBOutlet private weak var totalDurationLbl: UILabel!
    @IBOutlet private weak var totalClimbingLbl: UILabel!
    @IBOutlet private weak var totalCaloriesLbl: UILabel!
    
    lazy private var mapView: MapView = {
        let mapView: MapView = .init(frame: view.bounds)
        
        navigationLocationProvider = NavigationLocationProvider(locationManager: NavigationLocationManager())
        navigationLocationProvider.locationManager.allowsBackgroundLocationUpdates = false
        navigationLocationProvider.locationManager.delegate = self
        mapView.location.overrideLocationProvider(with: navigationLocationProvider)
        mapView.mapboxMap.setCamera(to: .init(zoom: 15))
        mapView.location.addLocationConsumer(newConsumer: self)
        mapView.location.locationProvider.startUpdatingLocation()
        mapView.location.options.puckType = .puck2D()
        mapView.ornaments.attributionButton.isHidden = true
        
        mapView.mapboxMap.onNext(event: .mapLoaded) { [weak self] _ in
            guard let self = self else {
                return
            }
            self.mapView.location.addLocationConsumer(newConsumer: self)
            self.navigationLocationProvider.locationManager.startUpdatingLocation()
        }
        mapView.gestures.panGestureRecognizer.addTarget(self, action: #selector(mapPanGestureReceived(_:)))
                
        return mapView
    }()
    
    // MARK: 中间设置变量
    private var startPoints: [CLLocationCoordinate2D] = []
    private var currentLinePoints: [CLLocationCoordinate2D] = []
    private var currentLastPoint: CLLocationCoordinate2D?
    private var currentPoint: CLLocationCoordinate2D?
    private var currentAlterHeight: CLLocationDistance?
    private var changeNewLine = false //点击了暂停，需要另起一条线
    private var lineIDs: [String] = []
    private var lineStrings: [LineString] = []
    private var lastLineString: LineString?
    private var isStarting = false {
        didSet {
            endButton.isEnabled = isStarting
        }
    }
    private var isNavigating = false {
        didSet {
            if isNavigating {
                pauseButton.setImage(.init(named: "map_navigation_pause"), for: .normal)
            } else {
                pauseButton.setImage(.init(named: "map_navigation_continue"), for: .normal)
            }
        }
    }
    private var navigationLocationProvider: NavigationLocationProvider!
    private var isCompletePending = false
    private var cid: Int = 0
    lazy private var startAnnotationView: UIImageView = .init(image: .init(named: "cycling_line_end_start"))
    lazy private var endAnnotationView: UIImageView = .init(image: .init(named: "cycling_line_end_icon"))
    private var mapHasTrackedByUser = false
    
    // MARK: 运行时间
    private var totalDuration: TimeInterval = 0
    private var timer: Timer?
    
    // MARK: 从路线详情页面携带的数据
    private var linesFromRouteDetail: LineString?
    private var lineIdFromRouteDetail: String?
    private var navigationRouteEndLocation: CLLocationCoordinate2D?
    private var navigationLineString: LineString?
    private var navigationRouteLineId: String?
    
    // MARK: 记录轨迹时处理退到后台的问题
    private var applicationDidEnterBackground = false
    private var userRouteUpdateInBackground = false
    
    // MARK: 模拟
    private var testPointIndex: Int = 0
    private var testPoints: [CLLocationCoordinate2D] = []
    
    // MARK: 声明周期方法
    override func viewDidLoad() {
        super.viewDidLoad()
        
        defaultSetup()
        mapContentStackView.addArrangedSubview(mapView)
        
        reloadCyclingLablesValue(clearToDefault: true)
        
        NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification(_:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(willEnterForegroundNotification(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        clearRouteLineFromRouteDetail()
    }
    
    // MARK: 事件处理方法
    @IBAction private func stopButtonAction(_ sender: Any) {
        if cid == 0 {
            endNavigation()
            return
        }
        if currentLinePoints.count == 0 {
            //未知错误，直接结束吧
            endNavigation()
            return
        }
        addEndAnnotation(withPoint: currentLinePoints.last!)
        
        let currentIsNavigating = isNavigating
        if isNavigating {
            pauseNavigation()
        }
        isCompletePending = true
        showAlert(withTitle: "确认结束本次活动?", message: nil, leftTitle: "结束", leftStyle: .default, leftBlock: { [weak self] in
            guard let self = self else {
                return
            }
            self.isNavigating = false
            MBProgressHUD.showAdded(to: self.view, animated: true)
            CSCyclingPlaceRequest.requestLocationInfo(withCoordinator: self.currentLinePoints.last!) { name in
                self.endNavigation(withEndLocationName: name ?? "未知地点")
            }
        }, rightTitle: "继续运动", rightStyle: .destructive) { [weak self] in
            self?.isCompletePending = false
            if currentIsNavigating {
                self?.continueNavigation()
            }
            self?.removeEndAnnotation()
        }
        
    }
    
    @IBAction private func pauseButtonAction(_ sender: Any) {
        if isStarting {
            if cid == 0 {
                return
            }
            let isCurrentNavigating = isNavigating
            MapRequest.postMapRequestAndRequestStatusFoAPI(Map_Riding_API_Suspendend, andParams: ["cid" : cid, "state" : (isNavigating ? 2 : 1) ]) { [weak self]success, reason in
                if(success) {
                    if isCurrentNavigating {
                        self?.pauseNavigation()
                    } else {
                        self?.continueNavigation()
                    }
                }
            }
        } else {
            requestStartCyclingData { [weak self]success, reason in
                if(!success) {
                    return
                }
                self?.startNavigation()
            }
        }
    }
    
    @objc private func mapPanGestureReceived(_ sender: Any) {
        mapHasTrackedByUser = true
        backOriginButton(willShow: true)
    }
    
    @IBAction private func showCurrentPointAction(_ sender: Any) {
        mapHasTrackedByUser = false
        if let currentPoint = currentPoint {
            mapView.mapboxMap.setCamera(to: .init(center: currentPoint))
        }
        backOriginButton()
    }
    
}

// MARK: 定位方法
extension CSCyclingRootViewController: LocationConsumer {
    
    func locationUpdate(newLocation: Location) {
        currentPoint = newLocation.coordinate
        currentAlterHeight = newLocation.location.altitude
        if navigationRouteEndLocation != nil && navigationLineString == nil {
            requestNavigationRouteToOrigin()
        }
        if isCompletePending {
            return
        }
        if !isNavigating {
            if !mapHasTrackedByUser {
                mapView.mapboxMap.setCamera(to: .init(center: newLocation.coordinate))
            }
        } else if !CSCyclingRootViewController.isInTestModel {
            currentPoint = newLocation.coordinate
            currentAlterHeight = newLocation.location.altitude
            if let currentPoint = currentPoint {
                addPointToLine(withPoint: currentPoint)
            }
        }
    }
}

// MARK: 对外访问方法
extension CSCyclingRootViewController {
    
    @objc func changeThisPage(withJsonModels jsonModels: [RouteDetailJsonModel]?) {
        guard let jsonModels = jsonModels else {
            return
        }
        showRouteLineFromRouteDetail(withPoints: jsonModels.reduce(into: [], { partialResult, model in
            partialResult.append(.init(latitude: model.lat, longitude: model.lng))
        }))
        if let linesFromRouteDetail = linesFromRouteDetail {
            showRouteLine(withLines: [linesFromRouteDetail])
        }
    }
    
    @objc func changeThisPage(withJsonModels jsonModels: [RouteDetailJsonModel]?, lat: CLLocationDistance, lng: CLLocationDistance) {
        if let jsonModels = jsonModels {
            showRouteLineFromRouteDetail(withPoints: jsonModels.reduce(into: [], { partialResult, model in
                partialResult.append(.init(latitude: model.lat, longitude: model.lng))
            }))
            if let linesFromRouteDetail = linesFromRouteDetail {
                showRouteLine(withLines: [linesFromRouteDetail])
            }
            
        }
        MBProgressHUD.showAdded(to: view, animated: true)
        
        navigationRouteEndLocation = .init(latitude: lat, longitude: lng)
        
        requestNavigationRouteToOrigin()
    }
    
}

// MARK: 工具类处理方法(更新路线)
private extension CSCyclingRootViewController {
    
    func addPointToLine(withPoint point: CLLocationCoordinate2D) {
        if startPoints.count == 0 || changeNewLine {
            //开始或者暂停之后开始了
            startPoints.append(point)
            if startPoints.count == 1 {
                addStartAnnotation(withPoint: point)
            }
            currentLinePoints.removeAll()
            lineIDs.append(createUniqueString())
            if lastLineString != nil {
                lineStrings.append(lastLineString!)
            }
            lastLineString = nil
        }
        
        currentLinePoints.append(point)
        showTrackingLine(withPoints: currentLinePoints)
//        showAllLines()
        mapView.camera.ease(to: .init(center: point), duration: 1)
    }
    
    func showTrackingLine(withPoints points: [CLLocationCoordinate2D]) {
        
        if applicationDidEnterBackground {
            userRouteUpdateInBackground = true
            return
        }
        
        let line = Turf.LineString(points)
        let sliced: LineString? = line
//        if points.count > 4 {
//            sliced = line.sliced(from: points[1], to: points[points.count - 1])
//        } else {
//            sliced = line
//        }
        guard let sliced = sliced else {
            return
        }
        guard let lineID = lineIDs.last else {
            return
        }
        
        lastLineString = sliced
        var geoSource = GeoJSONSource()
        geoSource.data = .feature(.init(geometry: .lineString(sliced)))
        if !mapView.mapboxMap.style.sourceExists(withId: lineID) {
            try? mapView.mapboxMap.style.addSource(geoSource, id: lineID)
        } else {
            try? mapView.mapboxMap.style.updateGeoJSONSource(withId: lineID, geoJSON: .geometry(.lineString(sliced)))
        }
        
        if !mapView.mapboxMap.style.layerExists(withId: lineID) {
            var layer: LineLayer = .init(id: lineID)
            layer.source = lineID
            layer.lineColor = .constant(.init(.color(withHexString: "#04DCA6")))
            layer.lineWidth = .constant(5)
            do {
                try mapView.mapboxMap.style.addPersistentLayer(layer)
            } catch {
                print("出现了错误，原因是:\(error)")
            }
        }
        
    }
    
}

// MARK: 工具类方法(默认设置)
private extension CSCyclingRootViewController {
    
    func defaultSetup() {
        
        isStarting = false
        isNavigating = false
                
        additionalSafeAreaInsets = .init(top: 0, left: 0, bottom: 60, right: 0)
    }
    
}

// MARK: 工具类方法(地图处理)
private extension CSCyclingRootViewController {
    
    //点击开始导航
    func startNavigation() {
        if !test_shouldStartNavigation() {
            return
        }
        
        mapView.mapboxMap.setCamera(to: .init(zoom: 16))
        
        MBProgressHUD.showAdded(to: view, animated: true)
        
        reloadCyclingCalculatedValues()
        
        startTimer()
        
        navigationLocationProvider.locationManager.requestAlwaysAuthorization()
        navigationLocationProvider.locationManager.allowsBackgroundLocationUpdates = true
        
        isStarting = true
        isNavigating = true
        
        heartBeatSetup()
        Heartbeat.sharedInstance.start()
        
        backOriginButton()
        
        if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
            appDelegate.shouldUseBackgroundTask = true
        }
    }
    
    //点击暂停
    func pauseNavigation() {
        if !isNavigating {
            return
        }
        isNavigating = false
        
        navigationLocationProvider.locationManager.allowsBackgroundLocationUpdates = false
        Heartbeat.sharedInstance.pause()
        
        pauseTimer()
    }
    
    //点击继续导航
    func continueNavigation() {
        if isNavigating {
            return
        }
        navigationLocationProvider.locationManager.allowsBackgroundLocationUpdates = true
        changeNewLine = true
        isNavigating = true
        Heartbeat.sharedInstance.start()
        startTimer()
    }
    
    //点击结束导航
    func endNavigation(withEndLocationName locationName: String? = nil) {
        if !isStarting {
            isCompletePending = false
            clearDataToDefault()
            return
        }
        
        guard let lastLocation = currentLinePoints.last else {
            clearDataToDefault()
            return
        }
        
        guard let image = currentMapViewImage() else {
            clearDataToDefault()
            return
        }
        guard let fileData = image.jpegData(compressionQuality: 1) else {
            clearDataToDefault()
            return
        }
        CyclingRequest.uploadImage(withFileData: fileData) { [weak self]imagePath in
            guard let self = self else {
                return
            }
            guard let imagePath = imagePath else {
                self.clearDataToDefault()
                return
            }
            CyclingRequest.postCyclingData(withApi: Map_Riding_API_Suspendend, params: ["cid" : self.cid, "state" : 3, "end_lng" : lastLocation.longitude, "end_lat" : lastLocation.latitude, "file" : imagePath ]) { [weak self]success, respondData, reason in
                guard let self = self else {
                    return
                }
                MBProgressHUD.hide(for: self.view, animated: true)
                if(success) {
                    self.pushToDetailVC()
                    self.clearDataToDefault()
                    self.clearRouteLineFromRouteDetail()
                } else {
                    guard let reason = reason else {
                        return
                    }
                    HUDHelper.showHudTipStr(reason)
                }
            }
        }
//        MapRequest.postMapRequestAndRequestStatusFoAPI(Map_Riding_API_Suspendend, andParams: ["cid" : cid, "state" : 3, "end_lng" : lastLocation.longitude, "end_lat" : lastLocation.latitude ], autoShowSuccessNotice: true) { [weak self]success, reason in
//            if(success) {
//                self?.clearDataToDefault()
//            }
//        }
        
    }
    
    //添加起始点图标
    func addStartAnnotation(withPoint point: CLLocationCoordinate2D) {
        if startPoints.count == 0 {
            return
        }
        let viewAnimation: ViewAnnotationOptions = ViewAnnotationOptions(
            geometry: Point(point),
            allowOverlap: true,
            anchor: .center
        )
//        let annotationView: UIView = .forAutoLayout(frame: .init(x: 0, y: 0, width: 120, height: 60))
//        annotationView.backgroundColor = .red
//        try? mapView.mapView.viewAnnotations.add(annotationView, options: viewAnimation)
        try? mapView.viewAnnotations.add(startAnnotationView, options: viewAnimation)
        MBProgressHUD.hide(for: view, animated: true)
    }
    
    //添加结束图标
    func addEndAnnotation(withPoint point: CLLocationCoordinate2D) {
        let viewAnimation: ViewAnnotationOptions = ViewAnnotationOptions(
            geometry: Point(point),
            allowOverlap: true,
            anchor: .center
        )
        try? mapView.viewAnnotations.add(endAnnotationView, options: viewAnimation)
    }
    
    //移除结束图标
    func removeEndAnnotation() {
        mapView.viewAnnotations.remove(endAnnotationView)
    }
    
    //判断当前点是否移动了
    func currentLocationHasChanged() -> Bool {
        guard let currentPoint = currentPoint, let currentLastPoint = currentLastPoint else {
            return false
        }
        return currentPoint != currentLastPoint
    }
    
    //清空数据
    func clearDataToDefault() {
        
        lineIDs.forEach {
            try? mapView.mapboxMap.style.removeSource(withId: $0)
            try? mapView.mapboxMap.style.removeLayer(withId: $0)
        }
        
        endTimer()
        totalDuration = 0
        
        mapView.viewAnnotations.remove(startAnnotationView)
        removeEndAnnotation()
        navigationLocationProvider.locationManager.allowsBackgroundLocationUpdates = false
        removeHeartSetup()
        
        currentLinePoints.removeAll()
        currentLastPoint = nil
        currentPoint = nil
        startPoints.removeAll()
        lineIDs.removeAll()
        lineStrings.removeAll()
        isStarting = false
        isNavigating = false
        lastLineString = nil
        isCompletePending = false
        
        testPointIndex = 0
        testPoints.removeAll()
        
        reloadCyclingLablesValue(clearToDefault: true)
        
        mapHasTrackedByUser = false
        
        if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
            appDelegate.shouldUseBackgroundTask = false
        }
        MBProgressHUD.hide(for: self.view, animated: true)
    }
    
    func showAllLines(_ animate: Bool = true) {
        
        if applicationDidEnterBackground {
            return
        }
        
        let lines = lineStrings + (lastLineString != nil ? [lastLineString!] : [])
        let geometry: Geometry = .geometryCollection(.init(geometries: lines.map({ $0.geometry })))
        var cameraOptions = mapView.mapboxMap.camera(for: geometry, padding: view.safeAreaInsets + .init(top: 20, left: 20, bottom: 20, right: 20), bearing: 0, pitch: 0)
        cameraOptions.zoom = min(cameraOptions.zoom ?? 0, mapView.mapboxMap.cameraState.zoom)
        mapView.camera.ease(to: cameraOptions, duration: animate ? 1.0 : 0)
    }
    
    func showRouteLine(withLines lines: [LineString]?) {
        guard let lines = lines else {
            return
        }
        mapHasTrackedByUser = true
        showOriginButton.isHidden = false
        let geometry: Geometry = .geometryCollection(.init(geometries: lines.map({ $0.geometry })))
        var cameraOptions = mapView.mapboxMap.camera(for: geometry, padding: view.safeAreaInsets + .init(top: 20, left: 20, bottom: 20, right: 20), bearing: 0, pitch: 0)
        cameraOptions.zoom = min(cameraOptions.zoom ?? 0, mapView.mapboxMap.cameraState.zoom)
        mapView.camera.ease(to: cameraOptions, duration: 1.0)
    }
}

// MARK: 工具类方法(数据处理)
private extension CSCyclingRootViewController {
    
    private static let heartBeatName = "MapCyclingRootViewController"
    
    func heartBeatSetup() {
        Heartbeat.sharedInstance.listen(name: CSCyclingRootViewController.heartBeatName, inteval: 3, times: 0) { [weak self]point in
            self?.sendBeatData()
        }
        
        test_heartBeatSetup()
    }
    
    func removeHeartSetup() {
        Heartbeat.sharedInstance.delisten(CSCyclingRootViewController.heartBeatName)
        
        test_removeBeartBeatSetup()
    }
    
    func sendBeatData() {
        if cid == 0 {
            return
        }
        guard let currentLocal = currentPoint else {
            return
        }
        let jsonString = (["lat" : currentLocal.latitude, "lng" : currentLocal.longitude, "alt" : currentAlterHeight ?? 0, "heartrate" : 0] as NSDictionary).mj_JSONString()
//        MapRequest.postNavigatingData(withParams: ["cid" : cid, "heartbeat" : jsonString as Any]) { success, reason in
//
//        }
        let params = ["cid" : cid, "heartbeat" : jsonString as Any]
        CyclingRequest.postCyclingData(withApi: Map_Riding_API_HeartBeat, params: params) { [weak self]succes, response, reason in
            if !succes {
                return
            }
            guard let cyclingModal = CyclingDataModel.yy_model(withJSON: response as Any) else {
                return
            }
            self?.reloadCyclingLablesValue(withModel: cyclingModal)
        }
    }
}

// MARK: 测试方法
private extension CSCyclingRootViewController {
    
    private static let test_heartBeatName = "test_MapCyclingRootViewController"
    private static let isInTestModel = false
    
    func test_heartBeatSetup() {
        if !CSCyclingRootViewController.isInTestModel {
            return
        }
        Heartbeat.sharedInstance.listen(name: CSCyclingRootViewController.test_heartBeatName, inteval: 2, times: 0) { [weak self] point in
            self?.test_changeLocation()
        }
    }
    
    func test_removeBeartBeatSetup() {
        if !CSCyclingRootViewController.isInTestModel {
            return
        }
        Heartbeat.sharedInstance.delisten(CSCyclingRootViewController.test_heartBeatName)
    }
    
    func test_changeLocation() {
        if testPointIndex >= testPoints.count - 1 {
            endNavigation()
            return
        }
        testPointIndex += 1
        currentPoint = testPoints[testPointIndex]
        if let currentPoint = currentPoint {
            addPointToLine(withPoint: currentPoint)
        }
    }
    
    //测试方法,非测试不用处理
    func test_shouldStartNavigation() -> Bool {
        if !CSCyclingRootViewController.isInTestModel {
            return true
        }
        if testPoints.count > 0 {
            return true
        }
        guard let jsonPath = Bundle.main.path(forResource: "RoutePoints", ofType: "geojson") else {
            return false
        }
        guard let jsonData = try? Data(contentsOf: URL(fileURLWithPath: jsonPath)) else {
            return false
        }
        guard let jsonDic = try? JSONDecoder().decode(Array<[String:Double]>.self, from: jsonData) else {
            return false
        }
        
        testPoints = jsonDic.reduce([], {
            $0 + [CLLocationCoordinate2D(latitude: $1["lat"] ?? 0, longitude: $1["lon"] ?? 0)]
        })
        return testPoints.count > 0
    }
    
}

extension CSCyclingRootViewController: CLLocationManagerDelegate {
    
    public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        navigationLocationProvider.didUpdateLocations(locations: locations)
    }
    
    public func locationManager(_ manager: CLLocationManager, didUpdateHeading heading: CLHeading) {
        navigationLocationProvider.delegate?.locationProvider(navigationLocationProvider, didUpdateHeading: heading)
    }
    
    public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        navigationLocationProvider.delegate?.locationProvider(navigationLocationProvider, didFailWithError: error)
    }

    @available(iOS 14.0, *)
    public func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        navigationLocationProvider.delegate?.locationProviderDidChangeAuthorization(navigationLocationProvider)
    }
    
}

// MARK: 数据请求
private extension CSCyclingRootViewController {
    
    func requestStartCyclingData(onComplete complete: ((Bool, String?) -> Void)?) {
        guard let currentPoint = currentPoint else {
            return
        }

        CSCyclingPlaceRequest.requestLocationInfo(withCoordinator: currentPoint) { [weak self]name in
            guard let name = name, name.count > 0 else {
                complete?(false, "没有获取到当前地址信息")
                return
            }
            self?.requestCreateRecord(withCurrentLocation: currentPoint, locationName: name, complete: complete)
        }
//        CyclingRequest.getAddressInfo(withParams: ["lon" : currentPoint.longitude, "lat" : currentPoint.latitude]) { [weak self]name in
//            guard let name = name, name.count > 0 else {
//                complete?(false, "没有获取到当前地址信息")
//                return
//            }
//            self?.requestCreateRecord(withCurrentLocation: currentPoint, locationName: name, complete: complete)
//        }
    }
    
    func requestCreateRecord(withCurrentLocation location: CLLocationCoordinate2D, locationName: String?, complete: ((Bool, String?) -> Void)?) {
        CyclingRequest.postCyclingData(withApi: Map_Riding_API_Start, params: ["equipmentid" : 1, "user_lng" : location.longitude, "user_lat" : location.latitude]) { [weak self]success, response, reason in
            if success {
                if let response = response as? [String:Any], let cidString = response["cid"] as? String, let cid = cidString.intValue {
                    self?.cid = cid
                    complete?(success, nil)
                } else {
                    complete?(false, "数据未返回")
                }
            } else {
                complete?(false, reason)
            }
        }
    }
    
}


// MARK: 工具类方法(更新UI)
private extension CSCyclingRootViewController {
    
    func reloadCyclingLablesValue(withModel cyclingModel: CyclingDataModel? = nil, clearToDefault: Bool = false) {
        guard let cyclingModel = cyclingModel else {
            if clearToDefault {
                totalDistanceLbl.text = "---"
                totalCaloriesLbl.text = "---"
                totalClimbingLbl.text = "---"
            }
            reloadCyclingCalculatedValues(toDefault: true)
            return
        }
        if cyclingModel.distance > 1000 {
            totalDistanceLbl.text = String(format: "%.0f m", cyclingModel.distance)
        } else {
            totalDistanceLbl.text = String(format: "%.1f km", cyclingModel.distance / 1000)
        }
        totalCaloriesLbl.text = String(format: "%.0f", cyclingModel.calories) + "kcal"
        totalClimbingLbl.text = cyclingModel.totalalt ?? "0m"
    }
    
    func reloadCyclingCalculatedValues(toDefault: Bool = false) {
        guard !toDefault else {
            totalDurationLbl.text = "---"
            return
        }
        totalDurationLbl.text = totalDurationString
    }
    
    //跳转到详情页面
    func pushToDetailVC() {
        guard cid != 0 else {
            return
        }
        let cyclingDetailVC = ActiveDetailViewController()
        cyclingDetailVC.cid = cid
        navigationController?.pushViewController(cyclingDetailVC, animated: true)
    }
    
    func currentMapViewImage() -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(mapView.frame.size, mapView.isOpaque, UIScreen.main.scale)
        
        mapView.drawHierarchy(in: mapView.bounds, afterScreenUpdates: false)
        
        guard let image = UIGraphicsGetImageFromCurrentImageContext() else { return nil }
        
        UIGraphicsEndImageContext()
        
        return image
    }
    
    func backOriginButton(willShow show: Bool = false) {
        if show {
            if isStarting {
                showOriginButton.isHidden = true
            } else {
                showOriginButton.isHidden = false
            }
        } else {
            showOriginButton.isHidden = true
        }
    }
    
}

// MARK: 处理运行时间的类
private extension CSCyclingRootViewController {
    
    private func startTimer() {
        if timer != nil {
            timer?.fireDate = .init()
            reloadCyclingCalculatedValues()
        } else {
            timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timeValueTickDown(_:)), userInfo: nil, repeats: true)
        }
    }
    
    private func pauseTimer() {
        timer?.fireDate = .distantFuture
    }
    
    private func endTimer() {
        timer?.invalidate()
        timer = nil
    }
    
    @objc func timeValueTickDown(_ sender: Any) {
        totalDuration += 1
        reloadCyclingCalculatedValues()
    }
    
    var totalDurationString: String {
        
        let hour = floor(totalDuration / 3600)
        let minute = floor((totalDuration - hour * 3600) / 60)
        let second = floor(totalDuration - hour * 3600 - 60 * minute)
        
        return String(format: "\(Int(hour)):%.2d:%.2d", Int(minute), Int(second))
        
    }
    
}

// MARK: 从路线详情页面携带的数据处理
private extension CSCyclingRootViewController {
    
    func showRouteLineFromRouteDetail(withPoints points:[CLLocationCoordinate2D]) {
        let line = Turf.LineString(points)
        let sliced: LineString? = line
//        if points.count > 4 {
//            sliced = line.sliced(from: points[1], to: points[points.count - 1])
//        } else {
//            sliced = line
//        }
        guard let sliced = sliced else {
            return
        }
        if(lineIdFromRouteDetail == nil) {
            lineIdFromRouteDetail = createUniqueString()
        }
        guard let lineIdFromRouteDetail = lineIdFromRouteDetail else {
            return
        }
        linesFromRouteDetail = sliced
        
        var geoSource = GeoJSONSource()
        geoSource.data = .feature(.init(geometry: .lineString(sliced)))
        if !mapView.mapboxMap.style.sourceExists(withId: lineIdFromRouteDetail) {
            try? mapView.mapboxMap.style.addSource(geoSource, id: lineIdFromRouteDetail)
        } else {
            try? mapView.mapboxMap.style.updateGeoJSONSource(withId: lineIdFromRouteDetail, geoJSON: .geometry(.lineString(sliced)))
        }
        
        if !mapView.mapboxMap.style.layerExists(withId: lineIdFromRouteDetail) {
            var layer: LineLayer = .init(id: lineIdFromRouteDetail)
            layer.source = lineIdFromRouteDetail
            layer.lineColor = .constant(.init(.color(withHexString: "#04DCA6")))
            layer.lineWidth = .constant(5)
            do {
                try mapView.mapboxMap.style.addPersistentLayer(layer)
            } catch {
                print("出现了错误，原因是:\(error)")
            }
        }
    }
    
    func clearRouteLineFromRouteDetail() {
        if isStarting {
            return
        }
        if let lineIdFromRouteDetail = lineIdFromRouteDetail {
            try? mapView.mapboxMap.style.removeSource(withId: lineIdFromRouteDetail)
            try? mapView.mapboxMap.style.removeLayer(withId: lineIdFromRouteDetail)
            self.linesFromRouteDetail = nil
            self.lineIdFromRouteDetail = nil
        }
        if let navigationRouteLineId = navigationRouteLineId {
            try? mapView.mapboxMap.style.removeSource(withId: navigationRouteLineId)
            try? mapView.mapboxMap.style.removeLayer(withId: navigationRouteLineId)
            self.navigationRouteLineId = nil
            navigationLineString = nil
            navigationRouteEndLocation = nil
        }
    }
    
}

// MARK: 处理推到后台不更新路线，进入前台需要在更新下路线
private extension CSCyclingRootViewController {
    
    @objc func didEnterBackgroundNotification(_ notification: Notification) {
        applicationDidEnterBackground = true
    }
    
    @objc func willEnterForegroundNotification(_ notification: Notification) {
        
        applicationDidEnterBackground = false
        
        if currentLinePoints.count > 0 && userRouteUpdateInBackground {
            showTrackingLine(withPoints: currentLinePoints)
//            showAllLines()
        }
        
        userRouteUpdateInBackground = false
    }
    
}

// MARK: 导航到起点
private extension CSCyclingRootViewController {
    
    func requestNavigationRouteToOrigin() {
        guard let startPoint = currentPoint, let endPoint = navigationRouteEndLocation else {
            return
        }
        
        let origin = Waypoint(coordinate: startPoint)
        let destination = Waypoint(coordinate: endPoint)
        
        DispatchQueue.global().async { [weak self] in
            guard let self = self else {
                return
            }
            
            let routeOptions = NavigationRouteOptions(waypoints: [origin, destination], profileIdentifier: .cycling)
            routeOptions.includesSpokenInstructions = true
            
            Directions.shared.calculate(routeOptions) { session, result in
                switch result {
                case .failure(_):
                    DispatchQueue.main.async {
                        self.navigationRouteEndLocation = nil
                        MBProgressHUD.hide(for: self.view, animated: true)
                    }
                case .success(let response):
                    // Pass the first generated route to the the NavigationViewController
                    guard let routes = response.routes, routes.count > 0 else {
                        DispatchQueue.main.async {
                            self.navigationRouteEndLocation = nil
                            MBProgressHUD.hide(for: self.view, animated: true)
                        }
                        return
                    }
                    DispatchQueue.main.async {
                        let route = routes.first!
                        self.navigationLineString = route.shape
                        self.showNavigationRouteLineFromRouteDetail(withLine: self.navigationLineString)
                        MBProgressHUD.hide(for: self.view, animated: true)
                    }
                }
            }
        }
        
    }
    
    func showNavigationRouteLineFromRouteDetail(withLine line: LineString?) {
        guard let line = line else {
            navigationLineString = nil
            navigationRouteLineId = nil
            navigationRouteEndLocation = nil
            return
        }
        let sliced: LineString? = line
//        if points.count > 4 {
//            sliced = line.sliced(from: points[1], to: points[points.count - 1])
//        } else {
//            sliced = line
//        }
        guard let sliced = sliced else {
            return
        }
        if(navigationRouteLineId == nil) {
            navigationRouteLineId = createUniqueString()
        }
        guard let navigationRouteLineId = navigationRouteLineId else {
            return
        }
        navigationLineString = sliced
        
        var geoSource = GeoJSONSource()
        geoSource.data = .feature(.init(geometry: .lineString(sliced)))
        if !mapView.mapboxMap.style.sourceExists(withId: navigationRouteLineId) {
            try? mapView.mapboxMap.style.addSource(geoSource, id: navigationRouteLineId)
        } else {
            try? mapView.mapboxMap.style.updateGeoJSONSource(withId: navigationRouteLineId, geoJSON: .geometry(.lineString(sliced)))
        }
        
        if !mapView.mapboxMap.style.layerExists(withId: navigationRouteLineId) {
            var layer: LineLayer = .init(id: navigationRouteLineId)
            layer.source = navigationRouteLineId
            layer.lineColor = .constant(.init(.red))
            layer.lineWidth = .constant(5)
            do {
                try mapView.mapboxMap.style.addPersistentLayer(layer)
            } catch {
                print("出现了错误，原因是:\(error)")
            }
        }
        
        showRouteLine(withLines: [sliced] + (linesFromRouteDetail != nil ? [linesFromRouteDetail!] : []))
    }
    
}
